package consoleui

import (
	"context"
	"fmt"
	"k8s.io/klog/v2"

	tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/dynamic"
)

const (
	kubernetesConsoleNS                = "kubedo-system"
	kubernetesConsoleRouteName         = "console"
	kubernetesPipelineNamespaceViewURL = "https://%s/pipelines/ns/%s/pipeline-runs"
	kubernetesPipelineDetailViewURL    = "https://%s/k8s/ns/%s/tekton.dev~v1~PipelineRun/%s"
	kubernetesPipelineTaskLogURL       = "%s/logs/%s"
	kubernetesRouteGroup               = "networking.k8s.io"
	kubernetesRouteVersion             = "v1"
	kubernetesRouteResource            = "ingresses"
	kubernetesConsoleName              = "kubernetes Console"
)

type KubernetesConsole struct {
	host string
}

func (o *KubernetesConsole) SetParams(_ map[string]string) {
}

func (o *KubernetesConsole) GetName() string {
	return kubernetesConsoleName
}

func (o *KubernetesConsole) URL() string {
	return "https://" + o.host
}

func (o *KubernetesConsole) DetailURL(pr *tektonv1.PipelineRun) string {
	return fmt.Sprintf(kubernetesPipelineDetailViewURL, o.host, pr.GetNamespace(), pr.GetName())
}

func (o *KubernetesConsole) TaskLogURL(pr *tektonv1.PipelineRun, taskRunStatus *tektonv1.PipelineRunTaskRunStatus) string {
	return fmt.Sprintf(kubernetesPipelineTaskLogURL, o.DetailURL(pr), taskRunStatus.PipelineTaskName)
}

func (o *KubernetesConsole) NamespaceURL(pr *tektonv1.PipelineRun) string {
	return fmt.Sprintf(kubernetesPipelineNamespaceViewURL, o.host, pr.GetNamespace())
}

// UI use dynamic client to get the route of the kubernetes
// console where we can point to.
func (o *KubernetesConsole) UI(ctx context.Context, kdyn dynamic.Interface) error {
	gvr := schema.GroupVersionResource{
		Group: kubernetesRouteGroup, Version: kubernetesRouteVersion, Resource: kubernetesRouteResource,
	}

	route, err := kdyn.Resource(gvr).Namespace(kubernetesConsoleNS).Get(ctx, kubernetesConsoleRouteName,
		metav1.GetOptions{})
	if err != nil {
		klog.Errorf("failed to get ingress %s from namespace %s. err=>%v", kubernetesConsoleRouteName, kubernetesConsoleNS, err)
		return err
	}
	spec, ok := route.Object["spec"].(map[string]interface{})
	if !ok {
		// this condition is satisfied if there's no metadata at all in the provided CR
		return fmt.Errorf("couldn't find spec in the Kubernetes Console route")
	}
	rules, ok := spec["rules"].([]interface{})
	if !ok {
		// this condition is satisfied if there's no metadata at all in the provided CR
		return fmt.Errorf("couldn't find spec.rules in the Kubernetes Console route")
	}

	rule, ok := rules[0].(map[string]interface{})
	if !ok {
		// this condition is satisfied if there's no metadata at all in the provided CR
		return fmt.Errorf("couldn't find rules.host in the Kubernetes Console route")
	}

	if o.host, ok = rule["host"].(string); !ok {
		// this condition is satisfied if there's no metadata at all in the provided CR
		return fmt.Errorf("couldn't find spec.host in the Kubernetes Console route")
	}

	return nil
}
